package org.datascooter.parser;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.datascooter.exception.DataScooterException;
import org.datascooter.inface.IXMLReader;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Provides information about mapping stored in XML files
 * 
 * @author nemo
 * 
 */
public class DOMReader implements IXMLReader {

	private String filePath;
	private List<SimpleElementReader> readerList = new ArrayList<DOMReader.SimpleElementReader>();
	private String nodeName;

	public DOMReader(String nodeName, String filePath) {
		this.nodeName = nodeName;
		this.filePath = filePath;
	}

	public void explore() throws SAXException, IOException, ParserConfigurationException {
		File file = new File(filePath);
		if (file.exists()) {
			Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file);
			List<Node> nodeList = searchName(doc.getDocumentElement());
			for (Node node : nodeList) {
				if (node == null || !node.getNodeName().equalsIgnoreCase(nodeName)) {
					throw new DataScooterException("Error unable to find root  :  " + nodeName);
				}
				readerList.add(new SimpleElementReader(node));
			}
		} else {
			throw new DataScooterException("*** File not found - " + filePath);
		}
	}

	private List<Node> searchName(Node node) {
		List<Node> result = new ArrayList<Node>();
		if (node.getNodeName().equalsIgnoreCase(nodeName)) {
			result.add(node);
		}
		NodeList childNodes = node.getChildNodes();
		for (int a = 0; a < childNodes.getLength(); a++) {
			Node item = childNodes.item(a);
			if (item.getNodeType() == Node.ELEMENT_NODE) {
				if (item.getNodeName().equalsIgnoreCase(nodeName)) {
					result.add(item);
				} else {
					result.addAll(searchName(item));
				}
			}
		}
		return result;
	}

	@Override
	public String getAttribute(String name) {
		return name;
	}

	@Override
	public IXMLReader[] getChildren(String name) {
		if (readerList.size() == 0) {
			return new IXMLReader[0];
		}
		return readerList.toArray(new IXMLReader[readerList.size()]);
	}

	@Override
	public String getNamespaceIdentifier() {
		return filePath;
	}

	@Override
	public String getValue(String name) {
		return name;
	}
	private class SimpleElementReader implements IXMLReader {

		private final Node childNode;
		private SimpleElementReader parent;

		public SimpleElementReader(Node node) {
			this.childNode = node;
			explore();
		}

		@Override
		public void explore() {
			NodeList childNodes = childNode.getChildNodes();
			for (int a = 0; a < childNodes.getLength(); a++) {
				Node item = childNodes.item(a);
				if (item.getNodeType() == Node.ELEMENT_NODE) {
					addChild(item).explore();
				}
			}
		}

		public SimpleElementReader addChild(Node node) {
			SimpleElementReader item = new SimpleElementReader(node);
			item.setParent(this);
			return item;
		}

		@Override
		public String getAttribute(String name) {
			Node namedItem = childNode.getAttributes().getNamedItem(name);
			if (namedItem == null) {
				return childNode.getNodeValue();
			}
			return namedItem.getNodeValue();
		}

		@Override
		public String toString() {
			return childNode.getNodeName() + " - " + childNode.getNodeValue();
		}

		@Override
		public IXMLReader[] getChildren(String name) {
			List<IXMLReader> list = new ArrayList<IXMLReader>();
			NodeList childNodes = childNode.getChildNodes();
			for (int a = 0; a < childNodes.getLength(); a++) {
				Node item = childNodes.item(a);
				if (item.getNodeType() == Node.ELEMENT_NODE) {
					if (item.getNodeName().equalsIgnoreCase(name)) {
						list.add(new SimpleElementReader(item));
					}
				}
			}
			return list.toArray(new IXMLReader[0]);
		}

		@Override
		public String getNamespaceIdentifier() {
			return childNode.getNodeName();
		}

		@Override
		public String getValue(String name) {
			Node namedItem = childNode.getAttributes().getNamedItem(name);
			if (namedItem == null) {
				return null;
			}
			return namedItem.getNodeValue();
		}

		@Override
		public String resolvePath(String attribute) {
			return attribute;
		}

		@SuppressWarnings("unused")
		public int getLevel() {
			if (parent == null) {
				return 0;
			} else {
				return parent.getLevel() + 1;
			}
		}

		@SuppressWarnings("unused")
		public SimpleElementReader getParent() {
			return parent;
		}

		public void setParent(SimpleElementReader parent) {
			this.parent = parent;
		}
	}

	@Override
	public String resolvePath(String attribute) {
		return attribute;
	}
}
